-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local state_machine = require 'service.upgrade_state_machine'
local bios_enum = require 'domain.bios_firmware.defs'
local signal = require 'interface.signal'
local upgrade_service = require 'service.upgrade_service'
local open_db = require 'bios.db'
local client = require 'bios.client'
local package_snapshot = require 'domain.bios_firmware.package.package_snapshot'

TestStateMachine= {}

local function test_state_machine_lock_success(machine)
    local ok = pcall(function()
        machine:lock(_, 'bios')
    end)
    lu.assertEquals(ok, true)
    machine:unlock('bios')
end

local function test_state_machine_lock_fail(machine)
    machine:run(bios_enum.UpgradeEvent.PrepareStart, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'PREPARE_START')
    local ok = pcall(function()
        machine:lock(_, 'bios')
    end)
    lu.assertEquals(ok, false)
    machine:run(bios_enum.UpgradeEvent.Error, 'bios')
end

local function test_state_machine_state_invalid(machine)
    lu.assertEquals(machine:get_state('bios'), 'UPGRADE_READY')
    local ok = pcall(function()
        machine:run(bios_enum.UpgradeEvent.PrepareFinish, 'bios')
    end)
    lu.assertEquals(ok, false)
    machine:run(bios_enum.UpgradeEvent.Error, 'bios')
end

local function test_state_machine_state_valid(machine)
    lu.assertEquals(machine:get_state('bios'), 'UPGRADE_READY')
    machine:run(bios_enum.UpgradeEvent.UpgradeReady, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'UPGRADE_READY')
    machine:run(bios_enum.UpgradeEvent.PrepareStart, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'PREPARE_START')
    machine:run(bios_enum.UpgradeEvent.PrepareFinish, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'PREPARE_FINISH')
    machine:run(bios_enum.UpgradeEvent.ProcessStart, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'PROCESS_START')
    machine:run(bios_enum.UpgradeEvent.ProcessFinish, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'PROCESS_FINISH')
    machine:run(bios_enum.UpgradeEvent.FimwareStart, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'FIRMWARE_FINISHING')
    machine:run(bios_enum.UpgradeEvent.FimwareFinish, 'bios')
    lu.assertEquals(machine:get_state('bios'), 'UPGRADE_READY')
end

function TestStateMachine:test_state_machine()
    local machine = state_machine.new()
    test_state_machine_lock_success(machine)
    test_state_machine_lock_fail(machine)
    test_state_machine_state_invalid(machine)
    test_state_machine_state_valid(machine)
end

local function construct_db()
    local ok, datas = pcall(require, 'bios.datas')
    if not ok then
        -- 如果没有datas配置，证明当前组件不需要datas，仅打开数据库
        datas = nil
    end
    local db = open_db(':memory:', datas)
    return db
end

local function construct_ctx()
    local ctx = {}
    ctx.ChanType = 1
    ctx.get_initiator = function()
        return {}
    end

    return ctx
end

function TestStateMachine:test_state_machine_instance()
    local upgrade_service_instance = upgrade_service.new(construct_db(), {})
    client.FirmwareActiveFirmwareActiveUpdateActiveStatus = function()
        return
    end
    client.FirmwareActiveFirmwareActiveActiveProcessReply = function()
        return
    end
    signal.activating = {}
    signal.power_off_effective_process(construct_ctx(), 1, 'Bios', upgrade_service_instance)
    signal.activating = {Bios = true}
    signal.power_off_effective_process(construct_ctx(), 1, 'Bios', upgrade_service_instance)

    local snapshot = package_snapshot.new(construct_db(), {ActivatedStatus = 1}, 1)
    upgrade_service_instance:register_multihost(bios_enum.BiosActiveRegisterList, snapshot)
    snapshot.is_cache = function()
        return true
    end

    client.FirmwareActiveFirmwareActiveRegisterActiveAction = function()
        return
    end
    upgrade_service_instance:register_multihost(bios_enum.BiosActiveRegisterList, snapshot)

    upgrade_service_instance.multihost = false
    upgrade_service_instance:judge_active_register(1)

    upgrade_service_instance.multihost = true
    upgrade_service_instance:judge_active_register(1)
    upgrade_service_instance:judge_active_register(255)
end

function TestStateMachine:test_wait_until_unlock()
    local machine = state_machine.new()
    local ok = pcall(function ()
        machine:wait_until_unlock(1)
    end)
    lu.assertEquals(ok, true)
    machine.lock_machine = true
    ok = pcall(function ()
        machine:wait_until_unlock(1)
    end)
    lu.assertEquals(ok, false)
    machine.lock_machine = false
end